package com.franklin.validation.core.argument.impl;

import com.franklin.validation.core.annotations.Resolver;
import com.franklin.validation.core.argument.interfaces.ResolverResult;
import com.franklin.validation.core.argument.interfaces.ResultFactory;
import com.franklin.validation.core.entity.CheckFormEntity;
import com.franklin.validation.core.entity.CheckResult;
import com.franklin.validation.core.utils.ReflectionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Description :
 * Create By: Franklin
 * Date : 2020/6/16 15:52
 */
public class ResultFactoryImpl implements ResultFactory<CheckFormEntity, CheckResult, Object> {

    @Autowired
    private ConfigurableApplicationContext applicationContext;

    private Map<Class,AbstractResolverResult> typeResolverMap;

    @PostConstruct
    public void init(){
        Map<String, Object> beansMap = this.applicationContext.getBeansWithAnnotation(Resolver.class);
        this.typeResolverMap = new HashMap<>(beansMap.size());
        beansMap.forEach((name,bean) -> {
            Class beanClass = bean.getClass();
            Resolver resolver = (Resolver) beanClass.getDeclaredAnnotation(Resolver.class);
            Class type = ReflectionUtil.getSuperClassGenericType(beanClass, 0);
            if (resolver.value() != String.class){
                this.typeResolverMap.put(resolver.value(),(AbstractResolverResult)bean);
            }else {
                this.typeResolverMap.put(type,(AbstractResolverResult)bean);
            }
        });
    }

    @Override
    public Object onError(CheckFormEntity input) {
        AbstractResolverResult abstractResolverResult = getAbstractResolverResult(input);
        return abstractResolverResult.onError(input);
    }

    private AbstractResolverResult getAbstractResolverResult(CheckFormEntity input) {
        Class<?> paramType = input.getParamType();
        if (List.class.isAssignableFrom(paramType)){
            paramType = List.class;
        }else if (Set.class.isAssignableFrom(paramType)){
            paramType = Set.class;
        }else if (Number.class.isAssignableFrom(paramType)){
            paramType = Number.class;
        }
        return this.typeResolverMap.get(paramType);
    }

    @Override
    public Object getResult(CheckFormEntity input) {
        return this.getAbstractResolverResult(input).getResult(input);
    }

    @Override
    public boolean checkSize(CheckFormEntity input) {
        return this.getAbstractResolverResult(input).checkSize(input);
    }

    @Override
    public CheckResult check(CheckFormEntity input) {
        return this.getAbstractResolverResult(input).check(input);
    }
}
